package conMgr.ui;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

import conMgr.model.Conference;
import conMgr.model.Paper;
import conMgr.model.Review;
import conMgr.model.Status;
import conMgr.model.User;
import conMgr.model.UserType;
import conMgr.ui.util.Ui;

/**
 * Represent list of papers of this conference.
 * @author Soon Bang.
 *
 */
public class ConferencePaperView extends JPanel implements Observer
{
	/**
	 * The serialization ID for this class.
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * The current conference.
	 */
	private final Conference my_conference;

	/**
	 * The current user.
	 */
	private final User my_user;
	
	/**
	 * The list of papers in this conference.
	 */
	private final List<Paper> my_papers;
	
	/**
	 * The selected paper.
	 */
	private static Paper my_paper;
	
	/**
	 * The paper table.
	 */
	private JTable my_table;
	
	/**
	 * Initializes a table of conference.
	 * @param the_conf The conference.
	 * @param the_user The User.
	 */
	public ConferencePaperView(final Conference the_conf, final User the_user)
	{
		my_conference = the_conf;
		my_user = the_user;
		my_papers = getUserPapers();
		addTable();
	}

	/**
	 * Adds the paper table to panel
	 * @return table The paper table.
	 */
	private JTable addTable()
	{
		final GridBagConstraints constraints = new GridBagConstraints();
		constraints.insets = Ui.DEFAULT_INSETS;
		constraints.gridx = 0;
		constraints.gridy = 0;
		constraints.anchor = GridBagConstraints.WEST;
		
		for (Paper paper : my_papers)
			paper.addObserver(this);
		
		final JTable table = new JTable(new PaperTableModel(my_papers));
		my_table = table;
		Ui.packTable(my_table);
		final DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer();
		cellRenderer.setHorizontalAlignment(SwingConstants.CENTER);
		
		//Center Alignment except paper title and author
		int c = 2;
		table.getColumnModel().getColumn(c++).setCellRenderer(cellRenderer);
		table.getColumnModel().getColumn(c++).setCellRenderer(cellRenderer);
		table.getColumnModel().getColumn(c++).setCellRenderer(cellRenderer);
		table.getColumnModel().getColumn(c++).setCellRenderer(cellRenderer);
		table.getColumnModel().getColumn(c++).setCellRenderer(cellRenderer);
		table.getColumnModel().getColumn(c++).setCellRenderer(cellRenderer);
			
		my_table.setRowSelectionAllowed(true);
		my_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		ListSelectionModel rowSM = my_table.getSelectionModel();
        rowSM.addListSelectionListener(new ListSelectionListener()
        {
            public void valueChanged(ListSelectionEvent e)
            {
            	final int row = my_table.getSelectedRow();
            	
            	if (row >= 0 && row < my_papers.size())
            		my_paper = my_papers.get(my_table.getSelectedRow());
            }
        });
    
		final JScrollPane pane = new JScrollPane(my_table);
		Dimension d = my_table.getPreferredSize();
		my_table.setPreferredScrollableViewportSize(d);
		add(pane, constraints);
		
		return my_table;
	}
	
	/**
	 * The selected Paper getter.
	 * @return my_paper The current selected paper.
	 */
	public static Paper getSelectedPaper()
	{
		return my_paper;
	}
	
	/**
	 * Gets a list of papers that the user has permissions to see.  
	 * @param the_user The user to check.
	 * @return A list of papers this user is authorized to see for this
	 * conference.
	 */
	public List<Paper> getUserPapers()
	{
		List<Paper> list;
		
		switch (User.getCurrentUser().getType())
		{
			case ADMIN:
				return my_conference.getPapers();
				
			case PROGRAM_CHAIR:
				list = new LinkedList<Paper>();
				if (my_conference.getProgramChair().equals(my_user))
					for(Paper paper : my_conference.getPapers())
						list.add(paper);
				return list;
				
			case SUBPROGRAM_CHAIR:
				list = new LinkedList<Paper>();
				for (Paper paper: my_conference.getPapers())
					if (paper.getSubprogramChair() == User.getCurrentUser())
						list.add(paper);
				return list;
				
			case AUTHOR:
				list = new LinkedList<Paper>(); 
				for (Paper paper : my_conference.getPapers())
					if (paper.getAuthor().equals(User.getCurrentUser()) ||
							paper.getStatus().equals(Status.ACCEPTED) ||
							paper.getStatus().equals(Status.REJECTED))
						list.add(paper);
				return list;
				
			case REVIEWER:
				list = new LinkedList<Paper>();
				for (Paper paper : my_conference.getPapers())
					for (Review review : paper.getPaperReviews())
						if (review.getReviewer().equals(User.getCurrentUser()))
							list.add(paper);
				return list;
			
			default:
				return new LinkedList<Paper>();
		}
	}
	/**
	 * Provides a table model for paper classes.
	 * @author Soon Bang.
	 */
	class PaperTableModel extends AbstractTableModel
	{
		/**
		 * The serialization ID of this class.
		 */
		private static final long serialVersionUID = 1L;
		/**
		 * The list of papers in this conference.
		 */
		private final List<Paper> my_papers;
		
		/**
		 * Initializes a new paper table model.
		 * @param the_papers
		 */
		private PaperTableModel(final List<Paper> the_papers)
		{
			my_papers = the_papers;
		}
		
		/**
		 * Gets the number of columns to display.
		 * Only program chair of this conference can see paper status.
		 */
		public int getColumnCount()
		{
			return 8;
		}
		
		/**
		 * Gets the name of the column at the specified index.
		 * @param column The column to get the name of.
		 * @return The name of the column at the specified index. 
		 */
		public String getColumnName(int column)
		{
			switch (column)
			{
				case 0: return "Title";
				case 1: return "Author";
				case 2: return "Categories";
				case 3: return "Keywords";
				case 4: return "Is reviewed?";
				case 5: return "Subprogram Chair";
				case 6: return "Is recommended?";
				case 7:	return "Status";
				default: return "";
			}
		};
		/**
		 * Gets the number of rows to display.
		 */
		public int getRowCount()
		{
			return my_papers.size();
		}
		/**
		 * Gets the value at the given row and column.
		 * @param row The row to get the value for.
		 * @param column The column to get the value for.
		 */
		public Object getValueAt(final int row, final int column)
		{
			final Paper paper = my_papers.get(row);
			
			switch (column)
			{
				case 0: return paper.getTitle();
				case 1: return paper.getAuthor().getName();
				case 2: return paper.getCategories();
				case 3: return paper.getKeywords();
				case 4: 
					if (paper.getSubprogramChair() == my_user || 
					my_conference.getProgramChair() == my_user || 
					my_user.getType() == UserType.ADMIN)
						if (paper.getPaperReviews().isEmpty())
							return "NO";
						else
							return "Yes";
					return "";
				case 5:
					if
					(
						paper.getSubprogramChair() != null &&
						(
							my_conference.getProgramChair() == my_user ||
							my_user.getType() == UserType.ADMIN
						)
					)
						return paper.getSubprogramChair().getName();
					return "";
				case 6: 
					if (paper.getSubprogramChair() == my_user || 
					my_conference.getProgramChair() == my_user || 
					my_user.getType() == UserType.ADMIN)
						if ((paper.getSubprogramChairRationale() == null))
							return "No";
						else
							return "Yes";
					return "";
				case 7:
					if (paper.getSubprogramChair() == my_user || 
					my_conference.getProgramChair() == my_user || 
					my_user.getType() == UserType.ADMIN)
						return paper.getStatus().getStatusName();
					else if (paper.getAuthor() == my_user &&
					paper.getStatus() == Status.ACCEPTED ||
					paper.getStatus() == Status.REJECTED)
						return paper.getStatus().getStatusName();
					return "";
				default: return "";
			}
		}
		/**
		 * Set the editable column which is last column and only Program Chair of
		 * this conference can see.
		 */
        public boolean isCellEditable(int row, int col)
        {
            return false;
        }
	}
	
	/**
	 * Refreshes the papers panel.
	 */
	@Override
	public void update(Observable arg0, Object arg1)
	{
		my_table.setModel(new PaperTableModel(my_papers));
	}
}
